package com.biodiv.miracle.ioc.scanner;

import com.biodiv.miracle.ioc.core.Resource;
import com.biodiv.miracle.support.utils.MiracleUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.logging.Logger;
/**
 * @Author: tianquan
 * @CreateTime: 2024-09-28  22:24
 * @Description: 实现了ClassLoad接口的类，用于扫描指定包下的所有类并加载，默认从application.properties文件中获取配置信息
 */
public class ClasspathScanner implements Resource {

    private final Logger logger = Logger.getLogger(ClasspathScanner.class.getName());
    private static final ClassLoader CLASS_LOADER = ClassLoader.getSystemClassLoader();
    protected final Properties properties;

    public ClasspathScanner() {
        this.properties = new Properties();
        try {
            InputStream resourceAsStream = CLASS_LOADER.getResourceAsStream("application.properties");
            if (resourceAsStream != null){
                properties.load(resourceAsStream);
            }
        } catch (Exception e) {
            logger.info("加载application.properties文件失败");
            throw new RuntimeException(e);
        }
    }

    /**
     * 扫描指定包名下的所有类，并将它们加载到 classNames 列表中
     *
     * @param packageName 要扫描的包的名称，例如"com.example.package"
     * @return 包含所加载类的列表
     */
    @Override
    public List<Class<?>> loadClass(String packageName) {
        // 存储找到的类
        List<Class<?>> classNames = new ArrayList<>();
        try {
            // 将包名转换为路径名
            String packagePath = packageName.replace('.', '/');
            // 获取包对应的资源路径
            Enumeration<URL> resources = ClassLoader.getSystemClassLoader().getResources(packagePath);
            while (resources.hasMoreElements()) {
                URL resource = resources.nextElement();
                File directory = new File(resource.getFile());
                if (directory.exists()) {
                    // 在目录中查找类
                    findClassesInDirectory(directory, packageName, classNames);
                }
            }
        } catch (IOException | ClassNotFoundException e) {
            // 打印异常信息
            e.printStackTrace();
        }
        return classNames;
    }

    @Override
    public String getEnvironmentVariable(String name) {
        return properties.getProperty(name);
    }

    @Override
    public InputStream getResource(String resourcePath) {
        return ClasspathScanner.class.getClassLoader().getResourceAsStream(resourcePath);
    }

    @Override
    public String getResourceAsString(String resourcePath) {
        try {
            // 使用类的加载器获取资源流
            InputStream inputStream = CLASS_LOADER.getResourceAsStream(resourcePath);
            if (inputStream == null) {
                throw new IOException("Resource not found: " + resourcePath);
            }
            // 读取输入流内容并转换为字符串
            try (ByteArrayOutputStream result = new ByteArrayOutputStream();
                 InputStream is = inputStream) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = is.read(buffer)) != -1) {
                    result.write(buffer, 0, length);
                }
                return result.toString(StandardCharsets.UTF_8);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 递归地在指定目录中查找所有的类，并将它们的类对象添加到 classNames 列表中
     *
     * @param directory   包含类文件的目录
     * @param packageName 目录对应的包名
     * @param classNames  存储找到的类的列表
     * @throws ClassNotFoundException 如果类加载失败
     */
    private static void findClassesInDirectory(File directory, String packageName, List<Class<?>> classNames) throws ClassNotFoundException {
        File[] files = directory.listFiles();
        if (files == null) {
            return;
        }
        for (File file : files) {
            if (file.isDirectory()) {
                // 递归处理子目录
                findClassesInDirectory(file, packageName + "." + file.getName(), classNames);
            } else if (file.getName().endsWith(".class")) {
                // 构建类名并加载类
                String className = packageName + "." + file.getName().substring(0, file.getName().length() - 6);
                classNames.add(MiracleUtils.getClassLoader().loadClass(className));
            }
        }
    }

}




